/* DBAccess The management of the connection to database.
 * The routine unifies the usage to database connection, 
 * including insertion and search.
 * */
package ncku.kdd.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.io.*;

import ncku.kdd.util.GlobalProperties;
import ncku.kdd.util.PropertyLoader;
import ncku.kdd.util.Propertyable;


/**
 * DBTask is used in charge of the management of the connection to database. We
 * unify the usage of database connection, including insertion and search in.
 * Note that we use signleton to realize the connection to the database to avoid
 * unnecessary multi-connection to the same database. 
 */
public class DataPool implements Propertyable {
	public static boolean DB_DEBUG = true;

	// using signleton to realize the connection to the database.
	private static DataPool me = null;

	private Connection conn = null;

	private Date nextUpdate;

	Calendar calendar = new GregorianCalendar();
	private Properties prop = null;
	

	public Properties loadDefaultProperties() {
		Properties p = new Properties();
		p.put("JDBC_DRIVER", "");
		p.put("JDBC_URL", "");
		p.put("JDBC_USER", "");
		p.put("JDBC_PASSWD", "");
		p.put("JDBC_Reconnection_Minutes", "");
		return p;
	}
	
	private DataPool() {
		calendar.setTime(Calendar.getInstance().getTime());
		calendar.add(Calendar.MINUTE, Integer.parseInt(prop
				.getProperty("JDBC_Reconnection_Minutes")));
		nextUpdate = calendar.getTime();
		PropertyLoader.load(this, GlobalProperties.DB_PROP_FILE);
		loadDriver();
	}

	public static DataPool getInstance() {
		if (me == null)
			me = new DataPool();
		return me;
	}

	public Connection getConnection() {
		Date now = Calendar.getInstance().getTime();
		if (now.after(nextUpdate)) {
			/*
			 * we may need to think another solution to re-connect database such
			 * as detecting if the connection is closed.
			 */
			try {
				conn = null;
				conn = DriverManager.getConnection(
						prop.getProperty("JDBC_URL"), prop
								.getProperty("JDBC_USER"), prop
								.getProperty("JDBC_PASSWD"));
				calendar.setTime(Calendar.getInstance().getTime());
				calendar.add(Calendar.MINUTE, Integer.parseInt(prop
						.getProperty("JDBC_Reconnection_Minutes")));
				nextUpdate = calendar.getTime();
				if (DB_DEBUG) {
					System.out.println("resetting the database connection");
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return conn;
	}

	/**
	 * support a quick and simple update
	 * 
	 * @param query
	 */
	public ResultSet simpleQuery(String query) {

		ResultSet rs = null;
		try {
			rs = conn.createStatement().executeQuery(query);

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rs;
	}

	/**
	 * support a quick update
	 * 
	 * @param query
	 */
	public void quickUpdate(String query) {
		Statement stmt = null;
		ResultSet rs = null;
		try {
			conn.createStatement().executeUpdate(query);
			conn.commit();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException sqlEx) { // ignore }
					rs = null;
				}
				if (stmt != null) {
					try {
						stmt.close();
					} catch (SQLException sqlEx) { // ignore }
						stmt = null;
					}
				}
			}
		}
	}

	private void loadDriver() {
		try {
			try {
				if (DB_DEBUG) {
					System.out.println("loading JDBC...");
				}
				Class.forName(prop.getProperty("JDBC_DRIVER")).newInstance();
				conn = DriverManager.getConnection(
						prop.getProperty("JDBC_URL"), prop
								.getProperty("JDBC_USER"), prop
								.getProperty("JDBC_PASSWD"));
				if (DB_DEBUG) {
					System.out.println("load JDBC completed.");
				}

			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}